redis入坑到放弃

传统来说 redis 能够做什么?

远程内存数据库 不仅性能强劲 而且还有复制特性以及为解决各种问题而生的独一无二的数据结构(致力于帮助用户解决问题,而不会像其他数据库那样,要求用户扭曲问题来适应数据库)。

同时 复制 持久化 客户端分片等特性 可以很快将redis 进行扩展成一个包含数百GB的数据、每秒处理上百万次请求的系统

服务器被关闭的时候 数据咋办?

redis 提供两种不同形式的持久化方案 一是时间点转储 二是只追加文件(append-only)

工具会极大形式地改变人们解决问题的方式

但是不能盲目地只是使用工具 还要弄清楚工具的工作原理 优劣 能否有改进的地方 这些都是很有必要的

redis VS memcached

使用redis 存储聚合数据有三个好处:

  • 将彼此相关的聚合数据放在同一个结构当中,这样访问数据就会变得更为容易;
  • 将聚合数据放到有序集合里,构建出一个实时排行榜
  • 聚合数据可以是整数或者浮点数 而memcached 只能是整数型的

数据结构:

  • 字符串

一个常见的用途就是 缓存用户信息。

将用户信息结构体使用json 序列化 字符串,然后将序列化后的字符串塞进redis缓存。同样,取用户信息会经过一次反序列化的过程。

redis 的字符串 是动态字符串,是可以修改的字符串,内部结构实现上类似java 的 arraylist,采用预分配冗余空间的方式来减少内存的频繁分配

过期和 set 命令扩展

可以对key 设置过期时间,到点自动删除。这个功能常用来控制缓存的实效时间。

计数功能: 如果value 是一个值, 还可以进行自增操作,自增是有范围的,它的范围是signed long 的最大最小值,超过了这个值 redis 会报错

字符串 是 由多个字节组成的,每个字节又是由8个bit组成,因此也可看成很多bit 的组合,这便是bitmap(位图)数据结构

  • 列表

相当与 java 中的 linkedlist 注意它是链表而不是数组

意味着插入和删除非常快 索引定位很慢

redis 的列表 常用来做异步队列使用 将需要延后处理的任务结构体 序列化成字符串 塞进 redis 的列表,另一个线程从这个列表中轮询数据进行处理

右进左出 队列

右边进 右边出 栈

慢操作

index 相当于 java 链表的 get(int index) 方法 它需要对链表进行遍历 性能随着参数index 增大而变差

ltrim 和字面上的含义不太一样,定义了一个区间 在这个区间内的值要保留 区间之外的统统砍掉 可以使用ltrim 来实现一个定长的链表 这一点非常有用

index=-1 表示倒数第一个元素

redis 底层存储的还不是一个 简单的 linkedlist 而是一个快速链表 quicklist 的结构

首先在列表元素较少的情况下 使用一块连续的内存存储 这个结构是ziplist 也即是压缩列表 所有的元素紧挨着一起存储 分配的是一块连续的内存 当数据量比较多的时候 才会改成 quicklist 因为普通的链表需要的附加指针空间太大,会比较浪费空间 而且会加重内存的碎片化 比如这个列表存的只是int 类型的数据 结构上还需要两个额外的指针prev 和 next 所以redis 将链表和ziplist 结合起来 组成了quicklist 也就是将多个ziplist 使用双指针串起来使用,这样既满足了快速的插入删除性能 也不会出现太大的空间冗余

  • 字典(散列)

相当于 java 中的 hashmap 是无序字典 内部实现也是一样 同样的数组+链表二维结构 第一维hash 的数组位置碰撞时 就会将碰撞的元素使用链表串接起来

不同的是 redis 中的字典 只能是字符串另外它们 rehash的方式 不一样 java的 hashmap 在字典很大的时候 rehash 是一个耗时的操作 需要一次性 rehash redis 为了提高性能 不能阻塞服务 采用了渐进式rehash 的策略

渐进式 rehash 会在rehash 的同时 保留新旧两个hash 结构 查询时会同时查询两个hash 结构 查询时会同时查询两个hash 结构 然后在后续的定时任务中 以及hash 操作指令中 循序渐进地将旧hash 的内容一点点迁移到新的hash 结构中 当搬迁完成了 就会用新的hash 结构取而代之

当hash 移除了最后一个元素 该数据结构自动被删除 内存被回收

  • 集合 set

集合和列表都可以存储多个字符串 集合通过不同的散列表来保证自己存储的每个字符串都是各不相同的(散列表只有键 没有与键相关联的值)
集合是无序的 因此 基本的几个命令为 sadd srem smembers sismember

集合常见操作 还有 并集 交集 差集

  • 有序集合 zset

有序集合和字典一样 都用于存储键值对 ;

有序集合的值被称为分值(score),分值必须为浮点数。

有序集合是redis中唯一一个既可以根据成员访问元素 又可以根据分值以及分值的排列顺序来访问元素的结构

有序集合命令 zadd zrem zrange(根据元素在有序排列中所处的位置,从有序集合里面获取多个元素)

zrangebyscore(获取有序集合在給定分值范围内的所有元素)

计数器 (数据搜集 指标量化)

计数器的更新

清理旧计数器

存储统计数据

查找ip所属城市以及国家(关系映射)

redis 的配置信息

在线配置

  • 一个标志位 web服务器是否在进行维护
  • 为每个独立部分都分别运行一个redis服务器,比如专门负责记录日志、统计数据、专门进行缓存、存储cookies等 一台机器上是可以运行多个redis服务器的 只要端口号各不相同 就可以了
  • 自动连接redis管理

自动补全的实现

分布式锁

一般对数据加锁 首先acquire 然后 release 对于多个线程访问的共享内存数据结构来说,这种先获取锁,然后执行操作,最后释放锁的动作非常常见。redis 使用watch 命令来代替对数据进行加锁 (乐观锁)